<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>2.写个机器人-1</title>
	<link rel="stylesheet" href="./index.css">
</head>

<body>
<canvas id="canvas"></canvas>
<script id="vertex-shader-3d" type="x-shader/x-vertex">
uniform mat4 u_worldViewProjection;
uniform vec3 u_lightWorldPos;
uniform mat4 u_world;
uniform mat4 u_viewInverse;
uniform mat4 u_worldInverseTranspose;
uniform mat4 u_matrix;
attribute vec4 a_position;
attribute vec3 a_normal;
attribute vec2 a_texcoord;

varying vec4 v_position;
varying vec2 v_texCoord;
varying vec3 v_normal;
varying vec3 v_surfaceToLight;
varying vec3 v_surfaceToView;

void main() {
  v_texCoord = a_texcoord;
  v_position = (u_matrix * a_position);
  v_normal = (u_worldInverseTranspose * vec4(a_normal, 0)).xyz;
  v_surfaceToLight = u_lightWorldPos - (u_world * a_position).xyz;
  v_surfaceToView = (u_viewInverse[3] - (u_world * a_position)).xyz;
  gl_Position = v_position;
}
</script>
<script id="fragment-shader-3d" type="x-shader/x-fragment">
precision mediump float;

varying vec4 v_position;
varying vec2 v_texCoord;
varying vec3 v_normal;
varying vec3 v_surfaceToLight;
varying vec3 v_surfaceToView;

uniform vec4 u_lightColor;
uniform vec4 u_colorMult;
uniform sampler2D u_diffuse;
uniform vec4 u_specular;
uniform float u_shininess;
uniform float u_specularFactor;

vec4 lit(float l ,//点光大小
float h,//高光大小
 float m) {
  return vec4(1.0,abs(l),(l > 0.0) ? pow(max(0.0, h), m) : 0.0,//如果有点光返回h或者0
              1.0);
}

void main() {
  vec4 diffuseColor = texture2D(u_diffuse, v_texCoord);//纹理
  vec3 a_normal = normalize(v_normal);//法线
  vec3 surfaceToLight = normalize(v_surfaceToLight);//光线到顶点向量
  vec3 surfaceToView = normalize(v_surfaceToView);//地对空方向
  vec3 halfVector = normalize(surfaceToLight + surfaceToView);//光线和法线中间值
  vec4 litR = lit(dot(a_normal, surfaceToLight),
                    dot(a_normal, halfVector), u_shininess);
  vec4 outColor = vec4((
  u_lightColor * (diffuseColor * litR.y * u_colorMult +//光线颜色和大小
                u_specular * litR.z * u_specularFactor)).rgb,//高光
      diffuseColor.a);//透明度
  gl_FragColor = vec4(1.,.0,.0,1);
}
</script>
<script src="https://webglfundamentals.org/webgl/resources/webgl-utils.js"></script>
<script src="https://webglfundamentals.org/webgl/resources/m4.js"></script>
<script src="https://webglfundamentals.org/webgl/resources/primitives.js"></script>
<script src="https://webglfundamentals.org/webgl/resources/texture-utils.js"></script>
<script src="https://webglfundamentals.org/webgl/resources/chroma.min.js"></script>
<script>
const canvas = document.querySelector("#canvas");
const gl = canvas.getContext("webgl");

webglUtils.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);

// Clear the canvas AND the depth buffer.
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

gl.enable(gl.CULL_FACE);
gl.enable(gl.DEPTH_TEST);

//获取program,获取着色器变量
const program = webglUtils.createProgramFromScripts(gl, ["vertex-shader-3d", "fragment-shader-3d"]);
var programInfo = webglUtils.createProgramInfo(gl, ["vertex-shader-3d", "fragment-shader-3d"]);

const uniformSetters = webglUtils.createUniformSetters(gl, program);
const attribSetters  = webglUtils.createAttributeSetters(gl, program);
//获取模型
var buffers = window.primitives.createSphereBuffers(gl, 18, 48, 48);

const cubeBufferInfo   = primitives.createCubeWithVertexColorsBufferInfo(gl, 1);
//材质制作
var textures = textureUtils.makeStripeTexture(gl, { color1: "#FFF", color2: "#FFF", })

var TRS = function() {
	this.translation = [0, 0, 0];
	this.rotation = [0, 0, 0];
	this.scale = [1, 1, 1];
};

TRS.prototype.getMatrix = function(dst) {
	dst = dst || new Float32Array(16);
	var t = this.translation;
	var r = this.rotation;
	var s = this.scale;
	m4.translation(t[0], t[1], t[2], dst);
	m4.xRotate(dst, r[0], dst);
	m4.yRotate(dst, r[1], dst);
	m4.zRotate(dst, r[2], dst);
	m4.scale(dst, s[0], s[1], s[2], dst);
	return dst;
};

class three{
	static object(){
		const myObj={}
		myObj.children = [];
		myObj.localMatrix = m4.identity();
		myObj.worldMatrix = m4.identity();
		myObj.parent=null
		myObj.add = function(obj) {
			myObj.children.push(obj)
			obj.parent=myObj
		};
		myObj.transform=function(x=0,y=0,z=0){
			m4.translate(myObj.localMatrix,x,y,z,myObj.localMatrix);
		}
		myObj.scale=function(x=1,y=1,z=1){
			m4.scale(myObj.localMatrix,x,y,z,myObj.localMatrix);
		}
		myObj.updateWorldMatrix = function() {//更新世界矩阵
			if (myObj.parent) {
				m4.multiply(myObj.parent.worldMatrix, myObj.localMatrix, myObj.worldMatrix);
			} else {
				m4.copy(myObj.localMatrix, myObj.worldMatrix);
			}
			var worldMatrix = myObj.worldMatrix;
			myObj.children.forEach(function(child) {
				child.updateWorldMatrix();
			});
		};
		return myObj
	}
}


const robot=three.object();//机器人
const head=three.object();//头
const headObj=three.object();//头

const hand=three.object();//身体
const handObj=three.object();//身体

const leftJoint=three.object();//左手
const leftJointObj=three.object();//左手
const leftArm1Obj=three.object();//左手
const leftArm2Obj=three.object();//左手
const leftArm1=three.object();//左手1
const leftArm2=three.object();//左手2

const rightJoint=three.object();//右手
const rightJointObj=three.object();//右手
const rightArm1Obj=three.object();//右手
const rightArm2Obj=three.object();//右手
const rightArm1=three.object();//右手1
const rightArm2=three.object();//右手2

const leftLeg=three.object();//左腿
const leftLegObj=three.object();//左腿
const leftThighObj=three.object();//左腿
const leftShankObj=three.object();//左腿

const leftThigh=three.object();//左大腿
const leftShank=three.object();//左小腿

const rightLeg=three.object();//右腿
const rightLegObj=three.object();//右腿
const rightThighObj=three.object();//右腿
const rightShankObj=three.object();//右腿
const rightThigh=three.object();//右大腿
const rightShank=three.object();//右小腿

robot.add(handObj)//添加身体
handObj.add(hand)//添加身体
handObj.add(headObj)//添加头
headObj.add(head)
leftJointObj.add(leftJoint)
rightJointObj.add(rightJoint)
leftLegObj.add(leftLeg)
rightLegObj.add(rightLeg)
handObj.add(leftJointObj)//添加左手
handObj.add(rightJointObj)//添加右手
handObj.add(leftLegObj)//添加左腿
handObj.add(rightLegObj)//添加右腿
//添加手关节
leftArm1Obj.add(leftArm1)
leftArm1Obj.add(leftArm2Obj)
leftArm2Obj.add(leftArm2)
rightArm1Obj.add(rightArm1)
rightArm1Obj.add(rightArm2Obj)
rightArm2Obj.add(rightArm2)

leftJointObj.add(leftArm1Obj)
rightJointObj.add(rightArm1Obj)
rightArm1Obj.add(rightArm2Obj)
//添加手关节

//添加腿关节
leftThighObj.add(leftThigh)
leftThighObj.add(leftShankObj)
leftShankObj.add(leftShank)
rightThighObj.add(rightThigh)
rightThighObj.add(rightShankObj)
rightShankObj.add(rightShank)

leftLegObj.add(leftThighObj)
rightLegObj.add(rightThighObj)
//添加腿关节
let keys=[
	"head",
	"hand",
	"leftJoint",
	"leftArm1",
	"leftArm2",
	"leftLeg",
	"leftThigh",
	"leftShank",
	"rightLeg",
	"rightThigh",
	"rightShank",
]
hand.transform(0,-5,0)
hand.scale(5,15,5)
head.transform(0,5,0)
head.scale(5,5,5)


leftJointObj.transform(0,0,0)
leftJoint.scale(5,5,5)
leftArm1Obj.transform(-5,0,0)
leftArm1.scale(5,5,5)
leftArm2Obj.transform(-5,0,0)
leftArm2.scale(5,5,5)

rightJointObj.transform(0,0,0)
rightJoint.scale(5,5,5)
rightArm1Obj.transform(5,0,0)
rightArm1.scale(5,5,5)
rightArm2Obj.transform(5,0,0)
rightArm2.scale(5,5,5)

leftLegObj.transform(-5,-10,0)
leftThighObj.transform(0,-5,0)
leftThigh.scale(5,5,5)
leftShankObj.transform(0,-5,0)
leftShank.scale(5,5,5)

rightLegObj.transform(5,-10,0)
rightThighObj.transform(0,-5,0)
rightThigh.scale(5,5,5)
rightShankObj.transform(0,-5,0)
rightShank.scale(5,5,5)
{
	head.drawInfo = {
		uniforms: {
			u_colorMult:             [1,0,0,1],
			u_diffuse:               textures,
			u_specular:              [1, 1, 1, 1],
			u_shininess:             100,
			u_specularFactor:        0.8,
		},
		programInfo: programInfo,
		bufferInfo: cubeBufferInfo,
	}
	hand.drawInfo = {
		uniforms: {
			u_colorMult:             [1,0,0,1],
			u_diffuse:               textures,
			u_specular:              [1, 1, 1, 1],
			u_shininess:             100,
			u_specularFactor:        0.8,
		},
		programInfo: programInfo,
		bufferInfo: cubeBufferInfo,
	}
	leftJoint.drawInfo = {
		uniforms: {
			u_colorMult:             [1,0,0,1],
			u_diffuse:               textures,
			u_specular:              [1, 1, 1, 1],
			u_shininess:             100,
			u_specularFactor:        0.8,
		},
		programInfo: programInfo,
		bufferInfo: cubeBufferInfo,
	}
	leftArm1.drawInfo = {
		uniforms: {
			u_colorMult:             [1,0,0,1],
			u_diffuse:               textures,
			u_specular:              [1, 1, 1, 1],
			u_shininess:             100,
			u_specularFactor:        0.8,
		},
		programInfo: programInfo,
		bufferInfo: cubeBufferInfo,
	}
	leftArm2.drawInfo = {
		uniforms: {
			u_colorMult:             [1,0,0,1],
			u_diffuse:               textures,
			u_specular:              [1, 1, 1, 1],
			u_shininess:             100,
			u_specularFactor:        0.8,
		},
		programInfo: programInfo,
		bufferInfo: cubeBufferInfo,
	}
	leftLeg.drawInfo = {
		uniforms: {
			u_colorMult:             [1,0,0,1],
			u_diffuse:               textures,
			u_specular:              [1, 1, 1, 1],
			u_shininess:             100,
			u_specularFactor:        0.8,
		},
		programInfo: programInfo,
		bufferInfo: cubeBufferInfo,
	}
	leftThigh.drawInfo = {
		uniforms: {
			u_colorMult:             [1,0,0,1],
			u_diffuse:               textures,
			u_specular:              [1, 1, 1, 1],
			u_shininess:             100,
			u_specularFactor:        0.8,
		},
		programInfo: programInfo,
		bufferInfo: cubeBufferInfo,
	}
	
	leftShank.drawInfo = {
		uniforms: {
			u_colorMult:             [1,0,0,1],
			u_diffuse:               textures,
			u_specular:              [1, 1, 1, 1],
			u_shininess:             100,
			u_specularFactor:        0.8,
		},
		programInfo: programInfo,
		bufferInfo: cubeBufferInfo,
	}
	
	rightJoint.drawInfo = {
		uniforms: {
			u_colorMult:             [1,0,0,1],
			u_diffuse:               textures,
			u_specular:              [1, 1, 1, 1],
			u_shininess:             100,
			u_specularFactor:        0.8,
		},
		programInfo: programInfo,
		bufferInfo: cubeBufferInfo,
	}
	
	rightArm1.drawInfo = {
		uniforms: {
			u_colorMult:             [1,0,0,1],
			u_diffuse:               textures,
			u_specular:              [1, 1, 1, 1],
			u_shininess:             100,
			u_specularFactor:        0.8,
		},
		programInfo: programInfo,
		bufferInfo: cubeBufferInfo,
	}
	
	rightArm2.drawInfo = {
		uniforms: {
			u_colorMult:             [1,0,0,1],
			u_diffuse:               textures,
			u_specular:              [1, 1, 1, 1],
			u_shininess:             100,
			u_specularFactor:        0.8,
		},
		programInfo: programInfo,
		bufferInfo: cubeBufferInfo,
	}
	
	leftShank.drawInfo = {
		uniforms: {
			u_colorMult:             [1,0,0,1],
			u_diffuse:               textures,
			u_specular:              [1, 1, 1, 1],
			u_shininess:             100,
			u_specularFactor:        0.8,
		},
		programInfo: programInfo,
		bufferInfo: cubeBufferInfo,
	}
	
	leftShank.drawInfo = {
		uniforms: {
			u_colorMult:             [1,0,0,1],
			u_diffuse:               textures,
			u_specular:              [1, 1, 1, 1],
			u_shininess:             100,
			u_specularFactor:        0.8,
		},
		programInfo: programInfo,
		bufferInfo: cubeBufferInfo,
	}
	
	leftShank.drawInfo = {
		uniforms: {
			u_colorMult:             [1,0,0,1],
			u_diffuse:               textures,
			u_specular:              [1, 1, 1, 1],
			u_shininess:             100,
			u_specularFactor:        0.8,
		},
		programInfo: programInfo,
		bufferInfo: cubeBufferInfo,
	}
	
	leftShank.drawInfo = {
		uniforms: {
			u_colorMult:             [1,0,0,1],
			u_diffuse:               textures,
			u_specular:              [1, 1, 1, 1],
			u_shininess:             100,
			u_specularFactor:        0.8,
		},
		programInfo: programInfo,
		bufferInfo: cubeBufferInfo,
	}
	
	leftShank.drawInfo = {
		uniforms: {
			u_colorMult:             [1,0,0,1],
			u_diffuse:               textures,
			u_specular:              [1, 1, 1, 1],
			u_shininess:             100,
			u_specularFactor:        0.8,
		},
		programInfo: programInfo,
		bufferInfo: cubeBufferInfo,
	}
	
	leftShank.drawInfo = {
		uniforms: {
			u_colorMult:             [1,0,0,1],
			u_diffuse:               textures,
			u_specular:              [1, 1, 1, 1],
			u_shininess:             100,
			u_specularFactor:        0.8,
		},
		programInfo: programInfo,
		bufferInfo: cubeBufferInfo,
	}
	
	leftShank.drawInfo = {
		uniforms: {
			u_colorMult:             [1,0,0,1],
			u_diffuse:               textures,
			u_specular:              [1, 1, 1, 1],
			u_shininess:             100,
			u_specularFactor:        0.8,
		},
		programInfo: programInfo,
		bufferInfo: cubeBufferInfo,
	}
	
	rightLeg.drawInfo = {
		uniforms: {
			u_colorMult:             [1,0,0,1],
			u_diffuse:               textures,
			u_specular:              [1, 1, 1, 1],
			u_shininess:             100,
			u_specularFactor:        0.8,
		},
		programInfo: programInfo,
		bufferInfo: cubeBufferInfo,
	}
	rightThigh.drawInfo = {
		uniforms: {
			u_colorMult:             [1,0,0,1],
			u_diffuse:               textures,
			u_specular:              [1, 1, 1, 1],
			u_shininess:             100,
			u_specularFactor:        0.8,
		},
		programInfo: programInfo,
		bufferInfo: cubeBufferInfo,
	}
	rightShank.drawInfo = {
		uniforms: {
			u_colorMult:             [1,0,0,1],
			u_diffuse:               textures,
			u_specular:              [1, 1, 1, 1],
			u_shininess:             100,
			u_specularFactor:        0.8,
		},
		programInfo: programInfo,
		bufferInfo: cubeBufferInfo,
	}
	
}

const objects=[
	head,
	hand,
	leftJoint,
	leftArm1,
	leftArm2,
	leftLeg,
	leftThigh,
	leftShank,
	rightLeg,
	rightThigh,
	rightShank,
	rightJoint,
	rightArm1,
	rightArm2,

]
const objectsToDraw=[
	head.drawInfo,
	hand.drawInfo,
	leftArm1.drawInfo,
	leftArm2.drawInfo,
	leftThigh.drawInfo,
	leftShank.drawInfo,
	rightThigh.drawInfo,
	rightShank.drawInfo,
	rightArm1.drawInfo,
	rightArm2.drawInfo,
	
	// leftLeg.drawInfo,
	// leftJoint.drawInfo,
	// rightLeg.drawInfo,
	// rightJoint.drawInfo,
]
// cubeBufferInfo

const camera={
	position:[0,0,100],
	target:[0,0,0],
	up:[0, 1, 0],
	matrix:m4.identity()
}

const model={
	radius: 100,
	position:[0,0,0],
    a_position: { buffer: buffers.position, numComponents: 3, },
    a_normal:   { buffer: buffers.normal,   numComponents: 3, },
    a_texcoord: { buffer: buffers.texcoord, numComponents: 2, },
	materialUniforms: {
		u_colorMult:             [1,1,0,1],
		u_diffuse:               textures,
		u_specular:              [1, 1, 1, 1],
		u_shininess:             100,
		u_specularFactor:        0.8,
	}
}
const light={
	u_lightWorldPos:         [-50, 30, 100],
	u_lightColor:            [1, 0, 0, 1],
};
var uniformsThatAreTheSameForAllObjects = {
	u_lightWorldPos:         [-50, 30, 100],
	u_viewInverse:           m4.identity(),
	u_lightColor:            [1, 1, 1, 1],
};
var worldUniforms = {
	u_worldViewProjection:   m4.identity(),
	u_world:                 m4.identity(),
	u_worldInverseTranspose: m4.identity(),
};
function degToRad(d) {
    return d * Math.PI / 180;
}

//开始设置着色器变量
// gl.useProgram(program);

// webglUtils.setAttributes(attribSetters, model);//设置模型
// webglUtils.setUniforms(uniformSetters, {
// 	...model.materialUniforms,//设置模型材质
// 	...worldUniforms,//设置世界变量
// 	...light,//设置光
// 	u_viewInverse:camera.matrix//设置视图矩阵u_viewInverse
// });
// gl.drawElements(gl.TRIANGLES, buffers.numElements, gl.UNSIGNED_SHORT, 0);
let t=0
function draw(){
	console.log("camera.position:",camera.position);
	t+=0.001
	camera.position=[
		Math.cos(t)*100,
		0,
		Math.sin(t)*100
	]
	//设置相机和投影
	var projectionMatrix =m4.perspective(degToRad(60), gl.canvas.clientWidth / gl.canvas.clientHeight, 1, 2000);
	var cameraMatrix = m4.lookAt(camera.position, camera.target, camera.up, camera.matrix);
	var viewMatrix = m4.inverse(cameraMatrix);
	var viewProjectionMatrix = m4.multiply(projectionMatrix, viewMatrix);
	m4.axisRotate(viewProjectionMatrix,[0,1,0],t,viewProjectionMatrix)

	m4.axisRotate(leftThigh.localMatrix,[1,0,0],t*0.001,leftThigh.localMatrix)
	m4.axisRotate(leftShank.localMatrix,[1,0,0],t*0.001,leftShank.localMatrix)
	m4.axisRotate(rightThigh.localMatrix,[1,0,0],t*0.001,rightThigh.localMatrix)
	m4.axisRotate(rightShank.localMatrix,[1,0,0],t*0.001,rightShank.localMatrix)

	//获取模型在世界的模型位置并转置
	var worldMatrix = m4.translation(...model.position);
	worldUniforms.u_world = worldMatrix;
	m4.multiply(viewProjectionMatrix, worldMatrix, worldUniforms.u_worldViewProjection);//和视图矩阵相乘获取u_worldViewProjection
	m4.transpose(m4.inverse(worldMatrix), worldUniforms.u_worldInverseTranspose);

	robot.updateWorldMatrix()
	objects.forEach(function(object) {
		object.drawInfo.uniforms.u_matrix = m4.multiply(viewProjectionMatrix, object.worldMatrix);
	});
	var lastUsedProgramInfo = null;
	var lastUsedBufferInfo = null;
	// objectsToDraw.forEach(function(object){
	// 	var programInfo = object.programInfo;
	// 	var bufferInfo = object.bufferInfo;
	// 	var bindBuffers = false;
	// 	if (programInfo !== lastUsedProgramInfo) {
	// 		lastUsedProgramInfo = programInfo;
	// 		gl.useProgram(programInfo.program);
	// 		bindBuffers = true;
	// 	}
	// 	if (bindBuffers || bufferInfo !== lastUsedBufferInfo) {
	// 		lastUsedBufferInfo = bufferInfo;
	// 		webglUtils.setBuffersAndAttributes(gl, programInfo, bufferInfo);
	// 	}
	// 	webglUtils.setUniforms(programInfo, object.uniforms);
	// 	gl.drawArrays(gl.TRIANGLES, 0, bufferInfo.numElements);
	// });
	objectsToDraw.forEach(function(object){
		var programInfo = object.programInfo;
		var bufferInfo = object.bufferInfo;
		var bindBuffers = false;
		if (programInfo !== lastUsedProgramInfo) {
			lastUsedProgramInfo = programInfo;
			gl.useProgram(programInfo.program);
			bindBuffers = true;
		}
		if (bindBuffers || bufferInfo !== lastUsedBufferInfo) {
			lastUsedBufferInfo = bufferInfo;
			webglUtils.setBuffersAndAttributes(gl, programInfo, bufferInfo);
		}
		webglUtils.setUniforms(programInfo, object.uniforms);
		gl.drawArrays(gl.TRIANGLES, 0, bufferInfo.numElements);
	});
requestAnimationFrame(draw)
}
requestAnimationFrame(draw)
</script>
</body>

</html>